use std::cell::RefCell;

pub trait Student {
    fn on_message(&self, msg: &str);
}

pub struct Teacher<'a, T: Student> {
    students: Vec<&'a T>
}

impl<'a, T:Student> Teacher<'a, T> {
    pub fn new () -> Teacher<'a, T> {
        Teacher {
            students: vec![]
        }
    }
    pub fn attach(&mut self, student: &'a T) {
        self.students.push(student)
    }
    pub fn notify(&self, msg: &str) {
        for student in self.students.iter() {
            student.on_message(msg);
        }
    }
}

// 首先定义一个男生类型
struct Boy {
    // 用于记录老师发过的消息
    messages: RefCell<Vec<String>>,
  }
  
  impl Boy {
    // 实现一个创建男生的方法
    fn new() -> Boy {
      Boy {
        messages: RefCell::new(vec![])
      }
    }
  }
  
  // 为男生实现学生的trait
  impl Student for Boy {
    fn on_message(&self, message: &str) {
      // 接受到老师的消息后存起来
      self.messages.borrow_mut().push(String::from(message)); // 报错，不能够把self.messages作为可变引用，因为&self是不可变引用
    }
  }

// Student定义了self不可变的on_message;而实际使用中, 又需要修改Boy中的messages, 所以, 给
// messages加上RefCell, 同时代码执行时使用borrow_mut这个内部方法; 这就是内部可变性



fn main() {
    // 一般情况下, 我们不能可变地借用一个不可变的值
    // let x = 5;
    // let y = &mut x; // 报错
    // 创建一个老师
    let mut teacher = Teacher::new();
    // 创建一个学生
    let student = Boy::new();
    // 老师关注这个学生
    teacher.attach(&student);
    // 老师通知所有学生
    teacher.notify("下课");

    println!("学生收到消息数量：{}", student.messages.borrow().len());
}
// 借用规则:
// 1. 在任何给定的时间里, 你要么拥有一个可变引用, 要么拥有多个不可变引用
// 2. 引用总是有效的

// RefCell<T> 和 Box<T>的区别
// 1. Box<T>在编译阶段就会强制要求代码遵守借用规则, 否则报错
// 2. RefCell<T> 则是在运行时检查借用规则, 否则触发panic

//  


//              Box<T>                       Rc<T>               RefCell<T>
// 同一数据所有这     1                             多个                多个
// 可变性、借用检查  可变/不可变借用(编译时检查)    不可变借用(编译时检查)  可变/不可变借用(运行时检查) 

// 内部可变性, 可变地借用一个不可变的值
